#include "tan_nbobject.h"
#include "tan_floatobject.h"
#include "tan_alloc.h"
#include "tan_nbmethod.h"

bool Tan_isFloat(const TAN_UINT8* float_str)
{
	TAN_INT32 find_count = 0;
	TAN_INT8* ptr_index = 0;
	TAN_INT32 str_len = strlen(float_str);

	for (int i = 0; i < str_len; i++)
	{
		if (float_str[i] > '9' || float_str[i] < '0')
		{
			if (float_str[i] != '.')
				return false;
		}
	}

	do
	{
		ptr_index = strchr(float_str, '.');
		if (ptr_index && (find_count < 2))
		{
			++find_count;
		}
	} while (ptr_index);

	if (find_count == 1) return true;
	else return false;
}

bool Tan_isNumber(const TAN_UINT8* number_str)
{
	TAN_INT32 str_len = strlen(number_str);

	for (int i = 0; i < str_len; i++)
	{
		if (number_str[i] > '9' || number_str[i] < '0')
		{
			return false;
		}
	}
	return true;
}

TanObject* Tan_Number_Copy(TanObject* number)
{
	TanNumberObject* number_object = 0;
	if (strcmp(number->object_type, "number") != 0) return Tan_Object_cast(number_object);

	number_object = (TanNumberObject*)Tan_AllocObject_Memset(sizeof(TanNumberObject));
	number_object->number = Tan_Number_cast(number)->number;
	Tan_Var_cast(number_object)->var_size = sizeof(TAN_INT64);
	Tan_Var_cast(number_object)->var_req = 1;
	Tan_Object_cast(number_object)->object_set = Tan_Object_cast(number)->object_set;
	Tan_Object_cast(number_object)->object_type = "number";

	return Tan_Object_cast(number_object);
}

static void number_delete(TanObject* oneself)
{
	free(oneself);
}

static void number_clear(TanObject* oneself)
{
	Tan_Number_cast(oneself)->number = 0;
}

static void number_repr(TanObject* oneself)
{
#ifdef TAN_OS_WINDOWS
	printf("%I64d", Tan_Number_cast(oneself)->number);
#elif defined(TAN_OS_LINUX)
	printf("%lld", Tan_Number_cast(oneself)->number);
#else
#endif
}

Tan_bool number_compare(TanObject* oneself, TanObject* other, TanCompareType type)
{
	if (strcmp(other->object_type, "float") == 0)
	{
		TAN_FLOAT _r_float = Tan_Float_cast(other)->float_var;

		if (type == Tan_compare_equal && Tan_Number_cast(oneself)->number == _r_float)
			return Tan_true;
		else if (type == Tan_compare_noequal && Tan_Number_cast(oneself)->number != _r_float)
			return Tan_true;
		else if (type == Tan_compare_greaterThan && Tan_Number_cast(oneself)->number > _r_float)
			return Tan_true;
		else if (type == Tan_compare_lessThan && Tan_Number_cast(oneself)->number < _r_float)
			return Tan_true;
		else if (type == Tan_compare_grea_equal && Tan_Number_cast(oneself)->number >= _r_float)
			return Tan_true;
		else if (type == Tan_compare_less_equal && Tan_Number_cast(oneself)->number <= _r_float)
			return Tan_true;
	}
	else if (strcmp(other->object_type, "number") == 0)
	{
		if (type == Tan_compare_equal && Tan_Number_cast(oneself)->number == Tan_Number_cast(other)->number)
			return Tan_true;
		else if (type == Tan_compare_noequal && Tan_Number_cast(oneself)->number != Tan_Number_cast(other)->number)
			return Tan_true;
		else if (type == Tan_compare_greaterThan && Tan_Number_cast(oneself)->number > Tan_Number_cast(other)->number)
			return Tan_true;
		else if (type == Tan_compare_lessThan && Tan_Number_cast(oneself)->number < Tan_Number_cast(other)->number)
			return Tan_true;
		else if (type == Tan_compare_grea_equal && Tan_Number_cast(oneself)->number >= Tan_Number_cast(other)->number)
			return Tan_true;
		else if (type == Tan_compare_less_equal && Tan_Number_cast(oneself)->number <= Tan_Number_cast(other)->number)
			return Tan_true;
	}
	else
	{
		Tan_RepError(0, "The data type is not of type 'number' or 'float'.", other);
	}
	return Tan_false;
}

static void number_assign(TanObject** oneself, TanObject* other, TanAssignType type)
{
	if (strcmp(other->object_type, "float") == 0)
	{
		TAN_FLOAT _float = Tan_Float_cast(other)->float_var;
		TAN_INT64 _number = Tan_Number_cast(*oneself)->number;
		tan_size_t _mem_size = Tan_Var_cast(*oneself)->var_size;
		tan_size_t _mem_req = Tan_Var_cast(*oneself)->var_req;

		TAN_FLOAT rt_float;

		if (type == Tan_assign_equal){
			rt_float = _float;
			goto NUMBER_ASSIGN_FLOAT_END1;
		}
		else if (type == Tan_assign_sum_equal){
			rt_float = _float + _number;
			goto NUMBER_ASSIGN_FLOAT_END1;
		}
		else if (type == Tan_assign_dif_equal){
			rt_float = _float - _number;
			goto NUMBER_ASSIGN_FLOAT_END1;
		}
		else if (type == Tan_assign_mul_equal){
			rt_float = _float * _number;
			goto NUMBER_ASSIGN_FLOAT_END1;
		}
		else if (type == Tan_assign_div_equal){
			rt_float = _float / _number;
			goto NUMBER_ASSIGN_FLOAT_END1;
		}
		else{
			Tan_RepError(false, "This operation cannot be operated by the data type 'number'.", other);
			return;
		}

	NUMBER_ASSIGN_FLOAT_END1:
		(*oneself)->object_set->type_delete(*oneself);
		*oneself = Tan_Float(rt_float);
		Tan_Var_cast(*oneself)->var_size = _mem_size;
		Tan_Var_cast(*oneself)->var_req = _mem_req;
	}
	else if (strcmp(other->object_type, "number") == 0)
	{
		if (type == Tan_assign_equal)
			Tan_Number_cast(*oneself)->number = Tan_Number_cast(other)->number;
		else if(type == Tan_assign_sum_equal)
			Tan_Number_cast(*oneself)->number += Tan_Number_cast(other)->number;
		else if (type == Tan_assign_dif_equal)
			Tan_Number_cast(*oneself)->number -= Tan_Number_cast(other)->number;
		else if (type == Tan_assign_mul_equal)
			Tan_Number_cast(*oneself)->number *= Tan_Number_cast(other)->number;
		else if (type == Tan_assign_div_equal)
			Tan_Number_cast(*oneself)->number /= Tan_Number_cast(other)->number;
		else if (type == Tan_assign_sum_sum)
			Tan_Number_cast(*oneself)->number++;
		else if (type == Tan_assign_dif_dif)
			Tan_Number_cast(*oneself)->number--;
		else
		{
			Tan_RepError(false, "This operation cannot be operated by the data type 'number'.", other);
			return;
		}
	}
	else
	{
		Tan_RepError(false, "The type cannot be operated on by the 'number' data type.", other);
	}
}

TanObject* number_operat(TanObject* oneself, TanObject* other, TanOperationType type)
{
	if (strcmp(other->object_type, "float") == 0)
	{
		TAN_INT64 _number = Tan_Number_cast(oneself)->number;
		TAN_FLOAT _float = Tan_Float_cast(other)->float_var;

		TAN_FLOAT rt_float = 0;
		if (type == Tan_operation_sum)
			rt_float = _number + _float; 
		else if(type == Tan_operation_dif)
			rt_float = _number - _float;
		else if (type == Tan_operation_mul)
			rt_float = _number * _float;
		else if (type == Tan_operation_div)
			rt_float = _number / _float;
		else
		{
			Tan_RepError(false, "This operation cannot be operated by the data type 'number'.", other);
			return 0;
		}

		return Tan_Float(rt_float);
	}
	else if (strcmp(other->object_type, "number") == 0)
	{
		TAN_INT64 _number_1 = Tan_Number_cast(oneself)->number;
		TAN_INT64 _number_2 = Tan_Number_cast(other)->number;

		TAN_INT64 rt_number = 0;
		if (type == Tan_operation_sum)
			rt_number = _number_1 + _number_2;
		else if (type == Tan_operation_dif)
			rt_number = _number_1 - _number_2;
		else if (type == Tan_operation_mul)
			rt_number = _number_1 * _number_2;
		else if (type == Tan_operation_div)
			rt_number = _number_1 / _number_2;
		else
		{
			Tan_RepError(false, "This operation cannot be operated by the data type 'number'.", other);
			return 0;
		}
		return Tan_Number(rt_number);
	}
	else
	{
		Tan_RepError(false, "The type cannot be operated on by the 'number' data type.", other);
	}
	return 0;
}

//static TanObjectMethod number_methods[] = { {"toString", Tan_NumberToString} };

//tanFunc_Method number_getmethod(const TAN_INT8* method_name)
//{
//	tanFunc_Method rt_func = 0;
//	TAN_INT32 numberMethod_size = sizeof(number_methods) / sizeof(TanObjectMethod);
//	
//	for (int i = 0; i < numberMethod_size; i++)
//	{
//		if (strcmp(number_methods[i].method_name, method_name) == 0) {
//			rt_func = number_methods[i].call_back;
//			break;
//		}
//	}
//	return rt_func;
//}

static TanObjectMethod number_methods[] =
{
	{ "toString" , number_toString }
};

tanFunc_Method number_find_method(const TAN_INT8* method_name)
{
	tan_size_t methods_size = sizeof(number_methods) / sizeof(TanObjectMethod);
	for (tan_size_t i = 0; i < methods_size; i++)
	{
		if (strcmp(number_methods[i].method_name, method_name))
			return number_methods[i].call_back;
	}
	return 0;
}

static TanObjectType number_object_Type =
{
	Tan_Number_Copy,// type_copy
	number_delete,	// type_delete
	number_clear,	// type_clear
	number_repr,	// var_repr
	number_compare,	// var_compare
	number_assign,	// var_assign
	number_operat,	// var_operation
	number_find_method,
	0				// next
};

TAN_INTERFACE_FUNC(TanObject*) Tan_Number_fromString(const TAN_INT8* str, tan_size_t len)
{
	TanNumberObject* var_object = 0;
	TAN_INT32 alloc_size = Tan_VarSizeOf;
	TAN_INT32 string_size = len ? len : strlen(str);

	TAN_INT8* alloc_float = (TAN_INT8*)malloc(string_size+1);
	if (alloc_float)
	{
		memset(alloc_float, 0, string_size + 1);
		memcpy(alloc_float, str, string_size);

		if (Tan_isFloat(alloc_float))
		{
			TanObject* object = Tan_Float_fromString(str, len);
			free(alloc_float);
			return object;
		}
		else if (Tan_isNumber(alloc_float))
		{
			var_object = Tan_AllocObject_Memset(sizeof(TanNumberObject));
			if (string_size == 1 && alloc_float[0] == '0')
				var_object->number = 0;
			else
			{
				var_object->number = _atoi64(alloc_float);
				if (var_object->number == 0)
				{
					Tan_RepError((TAN_INT32)var_object->number, 
						"Digital storage failed. It may be because the number of digits is too long."
					, 0);
				}
			}

			Tan_Var_cast(var_object)->var_size = sizeof(TAN_INT64);
			Tan_Var_cast(var_object)->var_req = 1;
			Tan_Object_cast(var_object)->object_set = &number_object_Type;
			Tan_Object_cast(var_object)->object_type = "number";
		}
		else
		{
			free(alloc_float);
			return 0;
		}
	}
	
	free(alloc_float);

	return Tan_Object_cast(var_object);
}

TAN_INTERFACE_FUNC(TanObject*) Tan_Number(const TAN_INT64 number)
{
	TanNumberObject* var_object = 0;

	var_object = Tan_AllocObject_Memset(sizeof(TanNumberObject));
	Tan_Var_cast(var_object)->var_size = sizeof(TAN_INT64);
	Tan_Var_cast(var_object)->var_req = 1;
	Tan_Object_cast(var_object)->object_set = &number_object_Type;
	Tan_Object_cast(var_object)->object_type = "number";
	var_object->number = number;

	return Tan_Object_cast(var_object);
}


